﻿using System.Windows.Controls;
using System.Windows;
using System.Windows.Media.Animation;
using System;

namespace NavFx
{
	/// <summary>
	/// Transitor that fades the old page out to leave the new page in it's place
	/// </summary>
	public class FadeTransitor: ITransitor
	{
		#region Private members

		private object target = null;
		private UserControl currentPage = null;
		private UserControl nextPage = null;

		#endregion

		#region Public members

		/// <summary>
		/// Target for displaying the page
		/// </summary>
		public object Target
		{
			get
			{
				return this.target;
			}

			set
			{
				if(value is Panel)
				{
					this.target = value;
				}
				else
				{
					throw (new TargetNotSupportedException("The object is not a valid target for FadeTransitor, which only supports Panel or elements that derive from it."));
				}
			}
		}

		/// <summary>
		/// Duration of transition from previous page to next page
		/// </summary>
		public TimeSpan Duration
		{
			get;
			set;
		}

		#endregion

		#region ITransitor Members

		/// <summary>
		/// Change to the page specified as next
		/// </summary>
		/// <param name="previousPage">Ignored for this implemenation</param>
		/// <param name="nextPage">Target page to be displayed</param>
		public void TransitionPage(IPage previousPage, IPage nextPage)
		{

			if(this.Target == null)
			{
				//No target set to contain the page control
				throw (new TargetNotSetException());
			}

			if(nextPage is UserControl)
			{
				//get the usercontrol interface of the previous page
				this.nextPage = nextPage as UserControl;
				this.currentPage = previousPage as UserControl;

				//set up the fade out animation
				TimeSpan fadeOutDuration = TimeSpan.FromSeconds(this.Duration.TotalSeconds / 2);
				Duration duration = new Duration(fadeOutDuration);

				DoubleAnimation fadeOutAnimation = new DoubleAnimation();
				fadeOutAnimation.Duration = duration;
				fadeOutAnimation.To = 0;

				//prepare a story board to do the fade out
				Storyboard fadeOutStoryBoard = new Storyboard();
				fadeOutStoryBoard.Duration = duration;
				fadeOutStoryBoard.Children.Add(fadeOutAnimation);
				fadeOutStoryBoard.Completed += new EventHandler(fadeOut_Completed);
				
				Storyboard.SetTarget(fadeOutAnimation, this.currentPage);
				Storyboard.SetTargetProperty(fadeOutAnimation, new PropertyPath("Opacity"));

				//start the fade out
				fadeOutStoryBoard.Begin();
			}
			else
			{
				throw (new PageTypeNotSupportedException("Only UserControl is supported as the base type for pages handled by the FadeTransitor"));
			}
		}



		/// <summary>
		/// Handles removal of the previous page after fade out and starts fade in
		/// </summary>
		private void fadeOut_Completed(object sender, EventArgs e)
		{
			Storyboard storyBoard = sender as Storyboard;
			storyBoard.Stop();

			((Panel)this.Target).Children.Remove(this.currentPage);
			this.currentPage = null;

			//set up the fade in animation
			TimeSpan fadeInDuration = TimeSpan.FromSeconds(this.Duration.TotalSeconds / 2);
			Duration duration = new Duration(fadeInDuration);

			DoubleAnimation fadeInAnimation = new DoubleAnimation();
			fadeInAnimation.Duration = duration;
			fadeInAnimation.From = 0;
			fadeInAnimation.To = 100;

			//prepare a story board to do the animation
			Storyboard fadeInStoryBoard = new Storyboard();
			fadeInStoryBoard.Duration = duration;
			fadeInStoryBoard.Children.Add(fadeInAnimation);
			fadeInStoryBoard.Completed += fadeIn_Completed;

			Storyboard.SetTarget(fadeInAnimation, this.nextPage);
			Storyboard.SetTargetProperty(fadeInAnimation, new PropertyPath("Opacity"));

			((Panel)this.Target).Children.Add(this.nextPage);

			fadeInStoryBoard.Begin();

		}



		/// <summary>
		/// Handles removal of the previous page after fade out and starts fade in
		/// </summary>
		private void fadeIn_Completed(object sender, EventArgs e)
		{
			Storyboard storyBoard = sender as Storyboard;
			storyBoard.Stop();
		}

		#endregion

		#region Constructors

		/// <summary>
		/// Default constructor
		/// </summary>
		public FadeTransitor()
		{
			this.Duration = TimeSpan.FromSeconds(2);
		}

		/// <summary>
		/// Constructore overload supporting setting of the target
		/// </summary>
		/// <param name="target">Target container for displaying the next page</param>
		public FadeTransitor(Panel target, TimeSpan duration)
		{
			this.Target = target;
			this.Duration = duration;
		}
		#endregion


	}
}
